#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

#define DEFAULT_PORT 5000
#define DEFAULT_ADDR INADDR_ANY

#define debug(...)  printf(__VA_ARGS__)

int main(int argc, char **argv) {
    int port = DEFAULT_PORT;
    int socket_fd = -1;
    int ret = 0;
    struct sockaddr_in serveraddr;
    struct sockaddr_in clientaddr;
    int client_addr_size = 0;

    if (argc > 1) {
        port = atoi(argv[1]);
    }

    /* Creating a Socket and getting a socket descriptor */
    socket_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (socket_fd < 0) {
        /* Unable to create the socket */
        debug("Unable to allocate the socket: %d\n", socket_fd);
        return -1;
    }

    debug("Socket created with fd=%d\n", socket_fd);
    /* Else, socket is ready. Sockaddr_in needs to be filled in */
    memset(&serveraddr, 0, sizeof(struct sockaddr_in));
    memset(&clientaddr, 0, sizeof(struct sockaddr_in));
    serveraddr.sin_family = AF_INET;
    /* Let the System allocate a port number to this socket for binding */
    serveraddr.sin_port = ntohl(port);
    /* Using up any valid IP address assigned to this machine */
    serveraddr.sin_addr.s_addr = htonl(DEFAULT_ADDR);

    debug("Calling bind for %d:%d\n", DEFAULT_ADDR, port);
    ret = bind(socket_fd, (struct sockaddr *) &serveraddr, sizeof(struct sockaddr_in));
    if (ret != 0) {
        debug("Unable to bind to socket created: %d\n", ret);
        /* Closing the socket created */
        close(socket_fd);
        return -1;
    }

    /* Setting the connection to listen and then into accept state */
    printf("Listening for connection \n");
    ret = listen(socket_fd, 10);
    if (ret < 0 ) {
        debug("Unable to listen to socket created: %d\n", ret);
        close(socket_fd);
        return -1;
    }

    while (1) {
        /* Ready to infinitely accept any connection coming in */
        client_addr_size = sizeof(client_addr_size);
        ret = accept(socket_fd, (struct sockaddr *)&clientaddr, &client_addr_size);
    }

    /* Work is done, closing the connection */
    shutdown(socket_fd, SHUT_RDWR);
    close(socket_fd);

}


